<template>
  <div class="jcx-table" :style="{ height: _height }" v-loading="loading">
    <div class="jcx-table-table" :style="{ height: _table_height }">
      <el-table v-bind="$attrs" :data="jcxDataList" :row-key="rowKey" :key="toggleIndex" ref="jcxTableRef"
                :height="height === 'auto' ? null : '100%'" :size="config.size" :border="config.border"
                :stripe="config.stripe" :summary-method="remoteSummary ? remoteSummaryMethod : summaryMethod"
                @sort-change="sortChange" @filter-change="filterChange">
        <slot name="default"></slot>
        <template v-for="(column, index) in jcxColumnList" :key="index">
          <el-table-column v-if="!column.hide" :column-key="column.prop" :label="column.label" :prop="column.prop"
                           :width="column.width" :sortable="column.sortable" :fixed="column.fixed"
                           :filters="column.filters" :align="column.align"
                           :filter-method="remoteFilter || !column.filters ? null : filterHandler"
                           :show-overflow-tooltip="column.showOverflowTooltip">
            <template #default="scope">
              <slot :name="column.prop" v-bind="scope">
                {{ scope.row[column.prop] }}
              </slot>
            </template>
          </el-table-column>
        </template>
        <slot name="operate"></slot>
        <el-table-column min-width="1"></el-table-column>
        <template #empty>
          <el-empty :description="emptyText" :image-size="100"></el-empty>
        </template>
      </el-table>
    </div>
    <div class="jcx-table-page" v-if="!hidePagination || !hideBar">
      <div class="jcx-table-pagination">
        <el-pagination v-if="!hidePagination" background :small="true" :layout="paginationLayout" :total="total"
                       :page-size="jcxPageSize" :page-sizes="pageSizeList" v-model:currentPage="currentPage"
                       @current-change="currentPageChange" @update:page-size="pageSizeChange"></el-pagination>
      </div>
      <div class="jcx-table-do" v-if="!hideBar">
        <el-button v-if="!hideRefresh" @click="handleRefresh" icon="el-icon-refresh" circle
                   style="margin-left: 15px"></el-button>
        <el-popover v-if="columnList" placement="top" title="列设置" :width="500" trigger="click" :hide-after="0"
                    @show="columnShow = true" @after-leave="columnShow = false">
          <template #reference>
            <el-button icon="el-icon-set-up" circle style="margin-left: 15px"></el-button>
          </template>
          <jcx-column ref="columnRef" v-if="columnShow" :column-list="jcxColumnList" @column-change="handleColumnChange"
                      @save="handleSaveColumnList" @back="handleResetColumnList"></jcx-column>
        </el-popover>
        <el-popover v-if="!hideSetting" placement="top" title="表格设置" :width="400" trigger="click" :hide-after="0">
          <template #reference>
            <el-button icon="el-icon-setting" circle style="margin-left: 15px"></el-button>
          </template>
          <el-form label-width="80px" label-position="left">
            <el-form-item label="表格尺寸">
              <el-radio-group v-model="config.size" size="small" @change="configSizeChange">
                <el-radio-button label="large">大</el-radio-button>
                <el-radio-button label="default">正常</el-radio-button>
                <el-radio-button label="small">小</el-radio-button>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="样式">
              <el-checkbox v-model="config.border" label="纵向边框"></el-checkbox>
              <el-checkbox v-model="config.stripe" label="斑马纹"></el-checkbox>
            </el-form-item>
          </el-form>
        </el-popover>
      </div>
    </div>
  </div>
</template>

<script setup>
import jcxColumn from "./column.vue";
import tableConfig from "./table.js";
import modal from "@/utils/modal";
import {computed, onActivated, onDeactivated, onMounted, ref, watch} from "vue";

const emit = defineEmits(['dataChange']);
const props = defineProps({
  // 表格高度
  height: {type: [String, Number], default: "100%"},
  // 隐藏分页
  hidePagination: {type: Boolean, default: false},
  // 隐藏操作栏
  hideBar: {type: Boolean, default: false},
  // 隐藏设置
  hideSetting: {type: Boolean, default: false},
  // 隐藏刷新
  hideRefresh: {type: Boolean, default: false},
  // 行数据唯一标识
  rowKey: {type: String, default: ""},
  // 表格大小
  size: {type: String, default: "default"},
  // 表格边框
  border: {type: Boolean, default: false},
  // 表格斑马纹
  stripe: {type: Boolean, default: false},
  // 分页布局
  paginationLayout: {type: String, default: tableConfig.paginationLayout},
  // 分页-页面大小
  pageSize: {type: Number, default: tableConfig.pageSize},
  // 分页-页面大小列表
  pageSizeList: {type: Array, default: tableConfig.pageSizeList},
  // 表格名称
  tableName: {type: String, default: ""},
  // API 对象
  apiObject: {type: Array, default: []},
  // API 参数列表
  apiParamObject: {type: Object, default: () => ({})},
  // 表格列列表
  columnList: {type: Array, default: []},
  // 表格数据列表
  dataList: {type: Array, default: []},
  // 是否开启远程排序
  remoteSort: {type: Boolean, default: false},
  // 是否开启远程过滤
  remoteFilter: {type: Boolean, default: false},
  // 是否远程合计
  remoteSummary: {type: Boolean, default: false},
  // 远程合计函数
  summaryMethod: {type: Function, default: null},
});

// 高度
const _height = computed(() => Number(props.height) ? Number(props.height) + "px" : props.height);
// 表格高度
const _table_height = computed(() => props.hidePagination && props.hideBar ? "100%" : "calc(100% - 50px)");
// 表格数据
const jcxDataList = ref([]);
// 列数据
const jcxColumnList = ref([]);
// 表格索引
const toggleIndex = ref(0);
// 配置
const config = ref({
  size: props.size,
  border: props.border,
  stripe: props.stripe,
});
// 表格数据为空时的提示
const emptyText = ref("暂无数据");
// 数据总条数
const total = ref(0);
// 页面大小
const jcxPageSize = ref(props.pageSize);
// 当前页
const currentPage = ref(1);
// 是否显示列
const columnShow = ref(false);
// 加载动画
const loading = ref(false);
// 组件是否激活
const isActive = ref(true);
// DOM 引用
const jcxTableRef = ref(null);
const columnRef = ref(null);
// 表格请求参数
const tableParams = ref(props.apiParamObject);
const prop = ref(null);
const order = ref(null);
const summary = ref({});

// 远程合计行处理
const remoteSummaryMethod = (param) => {
  const {columns} = param;
  const sums = [];
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = "合计";
      return;
    }
    const values = summary.value[column.property];
    if (values) {
      sums[index] = values;
    } else {
      sums[index] = "";
    }
  });
  return sums;
}

// 排序事件
const sortChange = (obj) => {
  if (!props.remoteSort) {
    return false;
  }
  if (obj.column && obj.prop) {
    prop.value = obj.prop;
    order.value = obj.order;
  } else {
    prop.value = null;
    order.value = null;
  }
  getData();
}

// 过滤事件
const filterChange = (filters) => {
  if (!props.remoteFilter) {
    return false;
  }
  Object.keys(filters).forEach((key) => {
    filters[key] = filters[key].join(",");
  });
  upData(filters);
}

// 页码发生变化事件
const currentPageChange = () => {
  getData();
}

// 页面大小变化事件
const pageSizeChange = (size) => {
  jcxPageSize.value = size;
  getData();
}

// 刷新表格
const handleRefresh = () => {
  jcxTableRef.value.clearSelection();
  getData();
}

// 列改变时
const handleColumnChange = (columnList) => {
  jcxColumnList.value = columnList;
  toggleIndex.value += 1;
}

// 自定义列保存
const handleSaveColumnList = async (columnList) => {
  columnRef.value.isSave = true;
  try {
    await tableConfig.saveColumnList(props.tableName, columnList);
  } catch (error) {
    modal.errorMessage("保存失败");
    columnRef.value.isSave = false;
  }
  modal.successMessage("保存成功");
  columnRef.value.isSave = false;
}

// 自定义列重置
const handleResetColumnList = async () => {
  columnRef.value.isSave = true;
  try {
    tableConfig.resetColumnList(props.tableName, props.columnList).then(response => {
      jcxColumnList.value = response;
    });
    columnRef.value.usercolumn = JSON.parse(JSON.stringify(jcxColumnList.value || []));
  } catch (error) {
    modal.errorMessage("重置失败");
    columnRef.value.isSave = false;
  }
  columnRef.value.isSave = false;
}

// 表格大小改变
const configSizeChange = () => {
  jcxTableRef.value.doLayout();
}

const getCustomColumn = async () => {
  tableConfig.getColumnList(props.tableName, props.columnList).then(response => {
    jcxColumnList.value = response;
  })
}

const getData = async () => {
  loading.value = true;
  const reqData = {
    [tableConfig.request.page]: currentPage.value,
    [tableConfig.request.pageSize]: jcxPageSize.value,
    [tableConfig.request.prop]: prop.value,
    [tableConfig.request.order]: order.value,
  };
  if (props.hidePagination) {
    delete reqData[tableConfig.request.page];
    delete reqData[tableConfig.request.pageSize];
  }
  Object.assign(reqData, tableParams.value);

  try {
    var res = await props.apiObject.get(reqData);
  } catch (error) {
    loading.value = false;
    emptyText.value = error.statusText;
    return false;
  }
  try {
    var response = tableConfig.parseData(res);
  } catch (error) {
    loading.value = false;
    emptyText.value = "数据格式错误";
    return false;
  }
  if (response.code !== tableConfig.successCode) {
    loading.value = false;
    emptyText.value = response.msg;
  } else {
    emptyText.value = "暂无数据";
    if (props.hidePagination) {
      jcxDataList.value = response.data || [];
    } else {
      jcxDataList.value = response.rows || [];
    }
    total.value = response.total || 0;
    summary.value = response.summary || {};
    loading.value = false;
  }
  jcxTableRef.value.setScrollTop(0);
  emit("dataChange", res, jcxDataList.value);
}

const upData = (params, page = 1) => {
  currentPage.value = page;
  jcxTableRef.value.clearSelection();
  Object.assign(tableParams.value, params || {});
  getData();
}

const reload = (params, page = 1) => {
  currentPage.value = page;
  tableParams.value = params || {};
  jcxTableRef.value.clearSelection();
  jcxTableRef.value.clearSort();
  jcxTableRef.value.clearFilter();
  getData();
}

// 本地过滤
const filterHandler = (value, row, column) => {
  const property = column.property;
  return row[property] === value;
}

// 插入行 unshiftRow
const unshiftRow = (row) => {
  jcxDataList.value.unshift(row);
}

// 插入行 pushRow
const pushRow = (row) => {
  jcxDataList.value.push(row);
}

// 根据key覆盖数据
const updateKey = (row, rowKey = props.rowKey) => {
  jcxDataList.value.filter((item) => item[rowKey] === row[rowKey]).forEach((item) => Object.assign(item, row));
}

// 根据index覆盖数据
const updateIndex = (row, index) => {
  Object.assign(jcxDataList.value[index], row);
}

// 根据index删除
const removeIndex = (index) => {
  jcxDataList.value.splice(index, 1);
}

// 根据index批量删除
const removeIndexes = (indexes = []) => {
  indexes.forEach((index) => {
    jcxDataList.value.splice(index, 1);
  });
}

// 根据key删除
const removeKey = (key, rowKey = props.rowKey) => {
  jcxDataList.value.splice(jcxDataList.value.findIndex((item) => item[rowKey] === key), 1);
}

// 根据keys批量删除
const removeKeys = (keys = [], rowKey = props.rowKey) => {
  keys.forEach((key) => {
    jcxDataList.value.splice(jcxDataList.value.findIndex((item) => item[rowKey] === key), 1);
  });
}

// 原生方法转发
const clearSelection = () => {
  jcxTableRef.value.clearSelection();
}

const toggleRowSelection = (row, selected) => {
  jcxTableRef.value.toggleRowSelection(row, selected);
}

const toggleAllSelection = () => {
  jcxTableRef.value.toggleAllSelection();
}

const toggleRowExpansion = (row, expanded) => {
  jcxTableRef.value.toggleRowExpansion(row, expanded);
}

const setCurrentRow = (row) => {
  jcxTableRef.value.setCurrentRow(row);
}

const clearSort = () => {
  jcxTableRef.value.clearSort();
}

const clearFilter = (columnKey) => {
  jcxTableRef.value.clearFilter(columnKey);
}

const doLayout = () => {
  jcxTableRef.value.doLayout();
}

const sort = (prop, order) => {
  jcxTableRef.value.sort(prop, order);
}

onMounted(() => {
  // 判断是否开启自定义列
  if (props.columnList) {
    jcxColumnList.value = props.columnList;
  }
  // 判断是否静态数据
  if (props.apiObject) {
    getData();
  } else if (props.dataList) {
    jcxDataList.value = props.dataList;
    total.value = jcxDataList.value.length;
  }
});

watch(() => props.dataList, (val) => {
  jcxDataList.value = props.dataList;
  total.value = jcxDataList.value.length;
});

watch(() => props.apiObject, (val) => {
  tableParams.value = props.apiParamObject;
  handleRefresh();
});

watch(() => props.columnList, (val) => {
  jcxColumnList.value = props.value.columnList;
});

onActivated(() => {
  if (!isActive.value) {
    jcxTableRef.value.doLayout();
  }
});

onDeactivated(() => {
  isActive.value = true;
});

// 输出组件的方法，让外部组件可以调用
defineExpose({
  upData,
})
</script>

<style scoped>
.jcx-table-table {
  height: calc(100% - 50px);
}

.jcx-table-page {
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 15px;
}

.jcx-table-do {
  white-space: nowrap;
}

.jcx-table:deep(.el-table__footer) .cell {
  font-weight: bold;
}

.jcx-table:deep(.el-table__body-wrapper) .el-scrollbar__bar.is-horizontal {
  height: 12px;
  border-radius: 12px;
}

.jcx-table:deep(.el-table__body-wrapper) .el-scrollbar__bar.is-vertical {
  width: 12px;
  border-radius: 12px;
}
</style>
